package com.mango.http;

import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.UUID;

import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.google.common.io.Files;
import com.mango.http.util.HttpKit;
import com.xiaoleilu.hutool.lang.Singleton;
import com.xiaoleilu.hutool.setting.Setting;
import com.xiaoleilu.hutool.util.ClassUtil;
import com.xiaoleilu.hutool.util.StrUtil;

import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.internal.StringUtil;

public class HttpServerInboundHandler2 extends SimpleChannelInboundHandler<FullHttpRequest> {
	public Logger log = Logger.getLogger(getClass());
	public static Setting app;
	public static String host;
	
	public HttpServerInboundHandler2() {
		app = new Setting("app.properties");
	}

	@SuppressWarnings({ "deprecation", "rawtypes", "unchecked" })
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
		String uri = request.getUri();
		host = request.headers().get("host");
		log.info(uri);
		String[] up = null;
		String path = uri;
		up = uri.split("\\?");
		path = up[0];
		String staticExts = app.getStr("app.static.exts");
		String ext = Files.getFileExtension(path);// 文件后缀
		if (!StringUtil.isNullOrEmpty(ext)) {
			if (Arrays.asList(staticExts.split(",")).contains(ext)) {
				//静态资源处理
				Singleton.get(HttpStaticFileServerHandler.class).channelRead0(ctx, request);
			} else {
				returnMsg(ctx,"不支持的后缀请求");
			}
		} else {
			//非静态请求，如后台请求，路由规则 /actionKey?a=1&b=2
			String reqKey = up[0];
			ParaSet ps = new ParaSet();
			if(up.length == 2){
				//有参数
				String params = up[1];
				String[] pp = params.split("&");
				for(String p : pp){
					String[] p1 = p.split("=");
					ps.put(p1[0], p1[1]);
				}
			}
			String indexKey = reqKey + "/index";
			indexKey = indexKey.replace("//", "/");
			if(IocFactory.reqKeyMap.containsKey(reqKey) || IocFactory.reqKeyMap.containsKey(indexKey)){
				if(IocFactory.reqKeyMap.containsKey(indexKey)){
					//默认方法
					reqKey = indexKey;
				}
				HttpMethod methodType = request.getMethod();
				if(methodType == HttpMethod.GET){
					
				}else if(methodType == HttpMethod.POST){
					String contentType = request.headers().get("Content-Type");
					
					String[] p = contentType.split(";");
					String dataType = p[0];
					String charset = p[1];
					charset = StrUtil.trimStart(charset);
					charset = charset.replaceAll("charset=", "");
					//有post参数
					String data = request.content().toString(Charset.forName(charset));
					if(dataType.equals("application/json")){
						//json格式
						JSONObject pjson = JSONObject.parseObject(data);
						for(String key : pjson.keySet()){
							ps.put(key, pjson.get(key).toString());
						}
					}else if(dataType.equals("application/x-www-form-urlencoded")){
						data = URLDecoder.decode(data, "utf-8");
						String[] pp2 = data.split("&");
						for(String p2 : pp2){
							String[] p22 = p2.split("=");
							ps.put(p22[0], p22[1]);
						}
					}
				}
				//有该请求 class#method
				String classMethod = IocFactory.reqKeyMap.get(reqKey);
				String[] p = classMethod.split("#");
				String actionClass = p[0];
				String actionMethod = p[1];
				Class clazz = Class.forName(actionClass);
				Object obj = ClassUtil.newInstance(clazz);
				
				DataSet ds = (DataSet) clazz.getMethod(actionMethod, ParaSet.class).invoke(obj, ps);
				if(ds.getType().equals(DataSet.HTML)){
					HtmlDataSet hds = (HtmlDataSet) ds;
					String html = HttpKit.get(app.getStr("app.protocol") + "://" + host + "/" + hds.getPath());
					returnHtml(ctx,html);
				}else if(ds.getType().equals(DataSet.JSON)){
					JsonDataSet jds = (JsonDataSet) ds;
					returnJson(ctx,JSONObject.toJSONString(jds));
				}else if(ds.getType().equals(DataSet.FILE)){
					//下载文件请求
					FileDataSet fds = (FileDataSet) ds;
					request.setUri(fds.getPath());
					Singleton.get(HttpFileDownloadHandler.class).channelRead0(ctx, request);
				}else if(ds.getType().equals(DataSet.FREEMARKER)){
					//渲染freemarker
					FreemarkerDataSet fds = (FreemarkerDataSet) ds;
					String templateStr = HttpKit.get(app.getStr("app.protocol") + "://" + host + "/" + fds.getPath());
					Configuration cfg = Singleton.get(Configuration.class);
			        StringTemplateLoader stringLoader = Singleton.get(StringTemplateLoader.class);
			        String uuid = UUID.randomUUID().toString();
			        stringLoader.putTemplate(uuid,templateStr);
			        cfg.setTemplateLoader(stringLoader);
			        try {
			            Template template = cfg.getTemplate(uuid,"utf-8");
			            StringWriter writer = new StringWriter();
			            try {
			                template.process(fds.getData(), writer);
			                returnHtml(ctx, writer.toString());
			            } catch (TemplateException e) {
			                e.printStackTrace();
			            }
			        } catch (IOException e) {
			            e.printStackTrace();
			        }
				}
			}else{
				returnMsg(ctx,"404");
			}
			
		}
		
	}
	/**
	 * 返回信息
	 * @param ctx
	 * @param msg
	 */
	private void returnMsg(ChannelHandlerContext ctx,String msg) {
		doReturn(ctx, msg, "text/plain");
	}
	
	private void returnHtml(ChannelHandlerContext ctx,String msg) {
		doReturn(ctx, msg,"text/html");
	}
	
	private void returnJson(ChannelHandlerContext ctx,String msg) {
		doReturn(ctx, msg, "application/json");
	}
	
	private void doReturn(ChannelHandlerContext ctx, String msg,String contentType) {
		try {
			FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
					Unpooled.wrappedBuffer(msg.getBytes("utf-8")));
			response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType);
			response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
			response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
			ctx.write(response);
			ctx.flush();
			ctx.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
	}
	
	@Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //ctx.fireExceptionCaught(cause);
		System.out.println("异常关闭请求，原因："+cause.getMessage());
		ctx.close();
    } 
}
